
import java.awt.AWTKeyStroke;
import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.KeyboardFocusManager;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import javax.swing.KeyStroke;
import javax.swing.ProgressMonitor;
import javax.swing.SwingWorker;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author TF
 */
public class MainFrame extends javax.swing.JFrame {

    /**
     * Creates new form MainFrame
     */
    public MainFrame() {
        initComponents();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jTabbedPane1 = new javax.swing.JTabbedPane();
        HWPanel = new javax.swing.JPanel();
        SWPanel = new javax.swing.JPanel();
        OTPanel = new javax.swing.JPanel();
        jMenuBar1 = new javax.swing.JMenuBar();
        fileMenu = new javax.swing.JMenu();
        openMenuItem = new javax.swing.JMenuItem();
        saveMenuItem = new javax.swing.JMenuItem();
        exitMenuItem = new javax.swing.JMenuItem();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setPreferredSize(new java.awt.Dimension(800, 600));

        javax.swing.GroupLayout HWPanelLayout = new javax.swing.GroupLayout(HWPanel);
        HWPanel.setLayout(HWPanelLayout);
        HWPanelLayout.setHorizontalGroup(
            HWPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 395, Short.MAX_VALUE)
        );
        HWPanelLayout.setVerticalGroup(
            HWPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 251, Short.MAX_VALUE)
        );

        jTabbedPane1.addTab("Hardware", HWPanel);

        javax.swing.GroupLayout SWPanelLayout = new javax.swing.GroupLayout(SWPanel);
        SWPanel.setLayout(SWPanelLayout);
        SWPanelLayout.setHorizontalGroup(
            SWPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 395, Short.MAX_VALUE)
        );
        SWPanelLayout.setVerticalGroup(
            SWPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 251, Short.MAX_VALUE)
        );

        jTabbedPane1.addTab("Software", SWPanel);

        javax.swing.GroupLayout OTPanelLayout = new javax.swing.GroupLayout(OTPanel);
        OTPanel.setLayout(OTPanelLayout);
        OTPanelLayout.setHorizontalGroup(
            OTPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 395, Short.MAX_VALUE)
        );
        OTPanelLayout.setVerticalGroup(
            OTPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 251, Short.MAX_VALUE)
        );

        jTabbedPane1.addTab("Shared ", OTPanel);

        getContentPane().add(jTabbedPane1, java.awt.BorderLayout.CENTER);

        fileMenu.setText("File");

        openMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK));
        openMenuItem.setText("Open");
        openMenuItem.setToolTipText("Open a raw file");
        openMenuItem.setBorderPainted(true);
        openMenuItem.setContentAreaFilled(false);
        openMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                openMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(openMenuItem);
        openMenuItem.getAccessibleContext().setAccessibleParent(fileMenu);

        saveMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_MASK));
        saveMenuItem.setText("Save");
        saveMenuItem.setToolTipText("Save to a raw file");
        saveMenuItem.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveMenuItemActionPerformed(evt);
            }
        });
        fileMenu.add(saveMenuItem);
        saveMenuItem.getAccessibleContext().setAccessibleParent(fileMenu);

        exitMenuItem.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_F4, java.awt.event.InputEvent.CTRL_MASK));
        exitMenuItem.setText("Exit");
        fileMenu.add(exitMenuItem);

        jMenuBar1.add(fileMenu);

        setJMenuBar(jMenuBar1);

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void saveMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveMenuItemActionPerformed
        // TODO add your handling code here:
//        Vector<String> rawfile = fc.updateRawContent();
        JFileChooser save = new JFileChooser();
        save.setFileFilter(new MyFilter(".props"));
        int returnVal = save.showSaveDialog(null);
        if (returnVal == JFileChooser.APPROVE_OPTION){
                File file = save.getSelectedFile();
                if(file.exists()){
                    int ans = JOptionPane.showConfirmDialog(save, "The file exists, overwrite?", "Existing file",JOptionPane.YES_NO_CANCEL_OPTION);
                    if(ans != JOptionPane.YES_OPTION){
                        return;
                    }
                }
                Vector<String> rawfile = fc.updateRawContent();
//                pm = null;
                final ProgressMonitor pm2 = new ProgressMonitor(save,"Saving...","", 0, 100);                
                pm2.setProgress(0);
                pm2.setMillisToDecideToPopup(100);
                pm2.setMillisToPopup(150);
                task1 = new EditorFileWriter(file,rawfile);
                task1.addPropertyChangeListener(new PropertyChangeListener(){
                    @Override
                    public void propertyChange(PropertyChangeEvent pce) {
                        int progress = 0;
                        String NewValue = pce.getNewValue().toString();
//                        System.out.println(pce.getNewValue());
                        if(NewValue.equalsIgnoreCase("STARTED")){
                            ;
                        } else if(NewValue.equalsIgnoreCase("DONE")){
                            ;
                        } else {
                            progress = Integer.parseInt(NewValue);
                        }
                        pm2.setProgress(progress);
                        String message = String.format("Completed %d%%.\n", progress);
                        pm2.setNote(message);
                        if (pm2.isCanceled() || task1.isDone()) {
                            Toolkit.getDefaultToolkit().beep();
                            task1.cancel(true);
                            pm2.close();
                        }                        
                        //throw new UnsupportedOperationException("Not supported yet.");
                    }                    
                });
                task1.execute();
//                FileWriter fw = new FileWriter(file.getAbsoluteFile());
//                BufferedWriter writer = new BufferedWriter(fw);
//                for(int i=0;i<rawfile.size();i++){
//                    writer.write(rawfile.get(i));
//                    writer.newLine();
//                }
//                writer.close();
                
        } 
            
        //System.out.println(evt.getActionCommand());
    }//GEN-LAST:event_saveMenuItemActionPerformed

    private void openMenuItemActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_openMenuItemActionPerformed
        JFileChooser open = new JFileChooser();
        open.setFileFilter(new MyFilter(".props"));
//        open.addChoosableFileFilter(new MyFilter(".raw"));
        String output = new String();
        String temp = new String();
        fc = new FileCache();
//        JPanel HWPanel = new JPanel();
//        JPanel SWPanel = new JPanel();
        GridLayout layout = new GridLayout(0,4);
        
//        HWPanel.setSize(600,400);
        HWPanel.setLayout(layout);
        SWPanel.setLayout(layout);
        OTPanel.setLayout(layout);
//        SWPanel.setSize(600,400);
//        SWPanel.setLayout(layout);
//        this.HWScrollPane.add(HWPanel);
//        this.SWScrollPane.add(SWPanel);
        int returnVal = open.showOpenDialog(open);
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            File file = open.getSelectedFile();
            final ProgressMonitor pm = new ProgressMonitor(open,
                                  "Loading...",
                                  "", 0, 100);
            pm.setProgress(0);
            pm.setMillisToDecideToPopup(100);
            pm.setMillisToPopup(150);
            task = new EditorFileReader(file,fc);
            task.addPropertyChangeListener(new PropertyChangeListener(){
                @Override
                public void propertyChange(PropertyChangeEvent pce) {
                    int progress = 0;
                    String NewValue = pce.getNewValue().toString();
                    if(NewValue.equalsIgnoreCase("STARTED")){
                            ;
                    } else if(NewValue.equalsIgnoreCase("DONE")){
                            ;
                    } else {
                            progress = Integer.parseInt(NewValue);
                    }
//                    System.out.println(pce.getNewValue());
                    pm.setProgress(progress);
                    String message = String.format("Completed %d%%.\n", progress);
                    pm.setNote(message);
                    if (pm.isCanceled() || task.isDone()) {
                        if(pm.isCanceled()){
                            Toolkit.getDefaultToolkit().beep();
                            task.cancel(true);
                            pm.close();
                            HWPanel.removeAll();
                            SWPanel.removeAll();
                            OTPanel.removeAll();
                        } else if(task.isDone()){
                            Toolkit.getDefaultToolkit().beep();
//                            task.cancel(true);
                            pm.close();
                        }
                    }
                    //throw new UnsupportedOperationException("Not supported yet.");
                }
                    
            });
            task.execute();
//            try {
//                FileReader fr = new FileReader(file);
////                FileInputStream fis = new FileInputStream(file);
////                JLabel filenameLabel = new JLabel(file.getName(), JLabel.RIGHT);
////                Object message[] = {"Reading:", filenameLabel};
////                ProgressMonitorInputStream pmis = new ProgressMonitorInputStream(null, "Reading:"+file.getName(), fis);
////                pmis.getProgressMonitor().setMillisToPopup(250);
////                InputStreamReader isr = new InputStreamReader(pmis);
//                BufferedReader reader = new BufferedReader(fr);
//                try {
//                    this.HWPanel.removeAll();
//                    this.SWPanel.removeAll();
//                    while((output = reader.readLine()) != null){
//                        fc.loadFile(output);
//                        if(output.contains("=") && !output.startsWith("*") && !output.startsWith("#")){
//                            if(output.startsWith("config.hw")){                                
//                                this.addLabel(HWPanel, fc.getCurrentName(),fc.getCurrentPro(),fc.getCurrentVal());
//                            }else if(output.startsWith("config.sw")){
//                                this.addLabel(SWPanel, fc.getCurrentName(),fc.getCurrentPro(),fc.getCurrentVal());
//                            }
//                            //this.HWScrollPane.validate();
//                            //fc.printItemArray();
//                        }
//                    }
//                } catch (IOException ex) {
//                    Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
//                }
//            } catch (FileNotFoundException ex) {
//                Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
//            }
            
            //printHashMap();
//            content = new HashMap<String,Properties>(fc.getHashMap());
        }
    }//GEN-LAST:event_openMenuItemActionPerformed

    
    class MyFilter extends javax.swing.filechooser.FileFilter{
        String endString = new String();
        public MyFilter(String end){
            endString = end;
        }
        @Override
        public boolean accept(File file) {
            String filename = file.getName();
            return filename.endsWith(endString) || file.isDirectory();
            //throw new UnsupportedOperationException("Not supported yet.");
        }

        @Override
        public String getDescription() {
            return endString; 
            //throw new UnsupportedOperationException("Not supported yet.");
        }        
    }
    public void invertFocusTraversalBehaviour(JTextArea textArea){
	Set<AWTKeyStroke> forwardKeys  = textArea.getFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS);
	Set<AWTKeyStroke> backwardKeys = textArea.getFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS);
 
		// check that we WANT to modify current focus traversal keystrokes
	if (forwardKeys.size() != 1 || backwardKeys.size() != 1) return;
	final AWTKeyStroke fks = forwardKeys.iterator().next();
	final AWTKeyStroke bks = backwardKeys.iterator().next();
	final int fkm = fks.getModifiers();
	final int bkm = bks.getModifiers();
	final int ctrlMask      = KeyEvent.CTRL_MASK+KeyEvent.CTRL_DOWN_MASK;
	final int ctrlShiftMask = KeyEvent.SHIFT_MASK+KeyEvent.SHIFT_DOWN_MASK+ctrlMask;
	if (fks.getKeyCode() != KeyEvent.VK_TAB || (fkm & ctrlMask) == 0 || (fkm & ctrlMask) != fkm){	// not currently CTRL+TAB for forward focus traversal
            return;
	}
	if (bks.getKeyCode() != KeyEvent.VK_TAB || (bkm & ctrlShiftMask) == 0 || (bkm & ctrlShiftMask) != bkm){	// not currently CTRL+SHIFT+TAB for backward focus traversal
            return;
	}
 
		// bind our new forward focus traversal keys
	Set<AWTKeyStroke> newForwardKeys = new HashSet<AWTKeyStroke>(1);
	newForwardKeys.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB,0));
	textArea.setFocusTraversalKeys(KeyboardFocusManager.FORWARD_TRAVERSAL_KEYS,Collections.unmodifiableSet(newForwardKeys)
		);
		// bind our new backward focus traversal keys
	Set<AWTKeyStroke> newBackwardKeys = new HashSet<AWTKeyStroke>(1);
	newBackwardKeys.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_TAB,KeyEvent.SHIFT_MASK+KeyEvent.SHIFT_DOWN_MASK));
	textArea.setFocusTraversalKeys(KeyboardFocusManager.BACKWARD_TRAVERSAL_KEYS,Collections.unmodifiableSet(newBackwardKeys));
 
		// Now, it's still useful to be able to type TABs in some cases.
		// Using this technique assumes that it's rare however (if the user
		// is expected to want to type TAB often, consider leaving text area's
		// behaviour unchanged...).  Let's add some key bindings, inspired
		// from a popular behaviour in instant messaging applications...
	TextInserter ti = new TextInserter();
        ti.applyTabBinding(textArea);
 
		// we could do the same stuff for RETURN and CTRL+RETURN for activating
		// the root pane's default button: omitted here for brevity
    }
    class TextInserter extends AbstractAction{
	private JTextArea textArea;
	private String insertable;
        public TextInserter(){}
	private TextInserter(JTextArea textArea, String insertable){
            this.textArea   = textArea;
            this.insertable = insertable;
	}
 	public void applyTabBinding(JTextArea textArea){
		textArea.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_TAB,KeyEvent.CTRL_MASK+KeyEvent.CTRL_DOWN_MASK),"tab");
		textArea.getActionMap().put("tab",new TextInserter(textArea, "\t"));
	}
 	public void actionPerformed(ActionEvent evt){
        	// could be improved to overtype selected range
            textArea.insert(insertable,textArea.getCaretPosition());
        }
    }
    class EditorFileWriter extends SwingWorker<Void,Void>{
        private File file;
        private Vector<String> rawfile;
        public EditorFileWriter(File f, Vector<String> rf){
            file = f;
            rawfile = rf;
        }
        @Override
        public Void doInBackground() throws Exception {
            int progress = 0;
            int size = rawfile.size();
            int percentage;
            this.setProgress(0);
            FileWriter fw = new FileWriter(file.getAbsoluteFile());
            BufferedWriter writer = new BufferedWriter(fw);
            for(int i=0;i<rawfile.size();i++){
                writer.write(rawfile.get(i));
                writer.newLine();
                progress++;
                percentage = (progress*100)/size;
                this.setProgress(percentage);
            }
            writer.close();
            return null; 
            //throw new UnsupportedOperationException("Not supported yet.");
        }
        @Override
        public void done(){
            this.setProgress(100);
        }
    }
    class EditorFileReader extends SwingWorker<Void,Void>{
        private String output;
        File file;
        FileCache fc;
        EditorFileReader(File f, FileCache fc1){
            file = f;
            fc = fc1;
            HWPanel.removeAll();
            SWPanel.removeAll();
            OTPanel.removeAll();
        }
        @Override
        public Void doInBackground() throws Exception {
            long progress = 0;
            long size;
//            long factor = 1;
            int percentage;
            this.setProgress(0);            
            try {
                java.io.FileReader fr = new java.io.FileReader(file);
//                FileInputStream fis = new FileInputStream(file);
                size=file.length();
//                InputStreamReader isr = new InputStreamReader(fis);
                BufferedReader reader = new BufferedReader(fr);
                try {
                    while((output = reader.readLine()) != null){                        
                        fc.loadFile(output);
                        if(output.contains("=") && !output.startsWith("*") && !output.startsWith("#") && fc.getCurrentName()!=null){
                            if(output.startsWith("config.hw")){                                
                                addLabel(HWPanel, fc.getCurrentName(),fc.getCurrentPro(),fc.getCurrentVal());
                            }else if(output.startsWith("config.sw")){
                                addLabel(SWPanel, fc.getCurrentName(),fc.getCurrentPro(),fc.getCurrentVal());
                            }else if(output.startsWith("config.line") || output.startsWith("config.test") || output.startsWith("config.shared")){
                                addLabel(OTPanel, fc.getCurrentName(),fc.getCurrentPro(),fc.getCurrentVal());
                            }
                            //this.HWScrollPane.validate();
                            //fc.printItemArray();
                        }
                        progress += (output.length()+2);
//                        if(progress > 70000000){
//                            factor++;
//                            progress -= 70000000;
//                        }
                        percentage=Math.min((int)(progress*100/size),100);
//                        System.out.println(progress+"/"+size);
                        this.setProgress(percentage);
//                        Thread.sleep(100);
                    }
                } catch (IOException ex) {
                    Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
                }
            } catch (FileNotFoundException ex) {
                Logger.getLogger(MainFrame.class.getName()).log(Level.SEVERE, null, ex);
            }
        //throw new UnsupportedOperationException("Not supported yet.");
        content = new HashMap<String,Properties>(fc.getHashMap());
        return null;
    }
    @Override
    public void done(){
        setProgress(100);
    }
   
}
    public void addLabel(javax.swing.JPanel p, String n, String pro, String v){
        javax.swing.JLabel label = new javax.swing.JLabel(n);
        javax.swing.JTextArea text = new javax.swing.JTextArea(v);
        text.setLineWrap(true);
        text.setWrapStyleWord(true);
        text.setName(pro);
        this.invertFocusTraversalBehaviour(text);
        text.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusLost(java.awt.event.FocusEvent evt) {
                TextAreaFocusLost(evt);
            }
        });
//        text.setAutoscrolls(true);
        JScrollPane scroll = new JScrollPane(text);
        
//        label.setSize(30, 14);
//        text.setSize(30, 250);
        label.setVisible(true);
        p.add(label);
        p.add(scroll);
        p.validate();
    }
    private void TextAreaFocusLost(java.awt.event.FocusEvent evt) {        
        JTextArea temp = (JTextArea)evt.getSource();
        String pro = temp.getName();
        String cur_val = temp.getText().trim();
        String prev_val = content.get(pro).val.trim();
//        System.out.println(fc.getRawContent(content.get(pro).index));
        if(!cur_val.equals(prev_val)){                        
            content.get(pro).val = cur_val;            
        }
        // TODO add your handling code here:
    }
    private FileCache fc;
    private HashMap<String,Properties> content;
//    private ProgressMonitor pm;
    private EditorFileReader task;
    private EditorFileWriter task1;
    /**
     * @param args the command line arguments
     */
    public static void main(String args[]) {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) {
                if ("Nimbus".equals(info.getName())) {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        } catch (ClassNotFoundException ex) {
            java.util.logging.Logger.getLogger(MainFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (InstantiationException ex) {
            java.util.logging.Logger.getLogger(MainFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (IllegalAccessException ex) {
            java.util.logging.Logger.getLogger(MainFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        } catch (javax.swing.UnsupportedLookAndFeelException ex) {
            java.util.logging.Logger.getLogger(MainFrame.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable() {
            public void run() {
                new MainFrame().setVisible(true);
            }
        });
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JPanel HWPanel;
    private javax.swing.JPanel OTPanel;
    private javax.swing.JPanel SWPanel;
    private javax.swing.JMenuItem exitMenuItem;
    private javax.swing.JMenu fileMenu;
    private javax.swing.JMenuBar jMenuBar1;
    private javax.swing.JTabbedPane jTabbedPane1;
    private javax.swing.JMenuItem openMenuItem;
    private javax.swing.JMenuItem saveMenuItem;
    // End of variables declaration//GEN-END:variables
}
